﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Silvermoon.Drawing
{
    public enum RawPixelFormat : int
    {
        Indexed = 0x00010000, // Indexes into a palette
        GDI = 0x00020000, // Is a GDI-supported format
        Alpha = 0x00040000, // Has an alpha component
        PAlpha = 0x00080000, // Pre-multiplied alpha
        Extended = 0x00100000, // Extended color 16 bits/channel
        Canonical = 0x00200000,

        Undefined = 0,
        DontCare = 0,

        Format1bppIndexed = (1 | (1 << 8) | Indexed | GDI),
        Format4bppIndexed = (2 | (4 << 8) | Indexed | GDI),
        Format8bppIndexed = (3 | (8 << 8) | Indexed | GDI),
        Format16bppRGB555 = (5 | (16 << 8) | GDI),
        Format16bppRGB565 = (6 | (16 << 8) | GDI),
        Format16bppARGB1555 = (7 | (16 << 8) | Alpha | GDI),
        Format24bppRGB = (8 | (24 << 8) | GDI),
        Format32bppRGB = (9 | (32 << 8) | GDI),
        Format32bppARGB = (10 | (32 << 8) | Alpha | GDI | Canonical),
        Format32bppPARGB = (11 | (32 << 8) | Alpha | PAlpha | GDI),
        //Format48bppRGB = (12 | (48 << 8) | Extended),
        //Format64bppARGB = (13 | (64 << 8) | Alpha | Canonical | Extended),
        //Format64bppPARGB = (14 | (64 << 8) | Alpha | PAlpha | Extended),
        Max = 15
    }

    public enum BufferDisposalFlag : int
    {
        None,
        GlobalFree,
        CoTaskMemFree,
        UnmapView
    }

    public enum InterpolationHint : int
    {
        Default,
        NearestNeighbor,
        Bilinear,
        Averaging,
        Bicubic
    }

    [Flags]
    public enum glImageLockMode
    {
        Read = 0x0001,
        Write = 0x0002,
        ReadWrite = 0x0003,
        UserInputBuffer = 0x0004,
    };

#pragma warning disable 0649
    [StructLayout(LayoutKind.Sequential)]
    public struct BitmapImageData
    {
        public int Width;
        public int Height;
        public int Stride;
        public RawPixelFormat PixelFormat;
        public IntPtr Scan0;
        public IntPtr Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ImageInfo
    {
        Guid RawDataFormat;
        public RawPixelFormat PixelFormat;
        public int Width;
        public int Height;
        public int TileWidth;
        public int TileHeight;
        public double Xdpi;
        public double Ydpi;
        public SinkFlags Flags;
    }

    [Flags]
    public enum SinkFlags : uint
    {
        None = 0,
        Scalable = 0x0001,
        HasAlpha = 0x0002,
        HasTranslucent = 0x0004,
        PartiallyScalable = 0x008,
        ColorSpaceRGB = 0x0010,
        ColorSpaceCMYK = 0x0020,
        ColorSpaceGray = 0x0040,
        ColorSpaceYCBCR = 0x080,
        ColorSpaceYCCK = 0x0100,
        Undef200 = 0x0200,
        Undef400 = 0x0400,
        Undef800 = 0x800,
        HasReaplDPI = 0x1000,
        HasRealPixelSize = 0x2000,
        FullWidth = 0x4000,
        Multipass = 0x8000,
        TopDown = 0x10000,
        BottumUp = 0x20000,
        Undef40000 = 0x40000,
        Unddef80000 = 0x80000,
        Composite = 0x100000,
        WantProps = 0x200000



    }

#pragma warning restore 0649

    [ComImport, Guid("327ABDA7-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImagingFactory
    {
        uint CreateImageFromStream();       
        uint CreateImageFromFile(string filename, out IImage image);
        uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
        uint CreateNewBitmap(uint width, uint height, RawPixelFormat pixelFormat, out IBitmapImage bitmap);
        uint CreateBitmapFromImage(IImage image, uint width, uint height, RawPixelFormat pixelFormat, InterpolationHint hints, out IBitmapImage bitmap);
        uint CreateBitmapFromBuffer();    
        uint CreateImageDecoder();         
        uint CreateImageEncoderToStream();  
        uint CreateImageEncoderToFile();   
        uint GetInstalledDecoders();    
        uint GetInstalledEncoders();     
        uint InstallImageCodec();         
        uint UninstallImageCodec();        
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public int Width
        {
            get
            {
                return Right - Left;
            }
            set
            {
                Right = Left + value;
            }
        }

        public int Height
        {
            get
            {
                return Bottom - Top;
            }
            set
            {
                Bottom = Top + value;
            }
        }

        public RECT(Rectangle rect)
        {
            Left = rect.Left;
            Top = rect.Top;
            Right = rect.Right;
            Bottom = rect.Bottom;
        }

        public RECT(int left, int top, int width, int height)
        {
            Left = left;
            Top = top;
            Right = left + width;
            Bottom = top + height;
        }

        public static implicit operator RECT(Rectangle rect)
        {
            return new RECT(rect);
        }
    }

    [ComImport, Guid("327ABDA9-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImage
    {
        uint GetPhysicalDimension(out Size size);
        uint GetImageInfo(out ImageInfo info);
        uint SetImageFlags(uint flags);
        uint Draw(IntPtr hdc, ref RECT dstRect, IntPtr srcRect); 
        uint PushIntoSink();  
        uint GetThumbnail(uint thumbWidth, uint thumbHeight, out IImage thumbImage);
    }

    [ComImport, Guid("327ABDAA-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IBitmapImage
    {
        uint GetSize(out Size size);
        uint GetPixelFormatID(out RawPixelFormat pixelFormat);
        uint LockBits(ref RECT rect, glImageLockMode flags, RawPixelFormat pixelFormat, out BitmapImageData lockedBitmapData);
        uint UnlockBits(ref BitmapImageData lockedBitmapData);
        uint GetPalette();  
        uint SetPalette(); 
    }
}
